package com.sunlee.admin.api.aspect;

import com.alibaba.fastjson.JSON;
import com.sunlee.admin.api.annotation.LogOperation;
import com.sunlee.admin.api.module.log.entity.SysLogOperationEntity;
import com.sunlee.admin.api.module.log.enums.OperationStatusEnum;
import com.sunlee.admin.api.module.log.service.SysLogOperationService;
import com.sunlee.admin.api.module.security.user.SecurityUser;
import com.sunlee.admin.api.module.security.user.UserDetail;
import com.sunlee.common.core.enums.ErrorCodeEnum;
import com.sunlee.common.core.utils.HttpContextUtils;
import com.sunlee.common.core.utils.IpUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 操作日志，切面处理类
 *

 * @author sunlee
 */
@Aspect
@Component
@Slf4j
public class LogOperationAspect {

    @Autowired
    private SysLogOperationService sysLogOperationService;

    @Pointcut("@annotation(com.sunlee.admin.api.annotation.LogOperation)")
    public void logPointCut() {
        //do nothing
    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        try {
            //执行方法
            Object result = point.proceed();

            //执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;
            //保存日志
            saveLog(point, time, OperationStatusEnum.SUCCESS.value());

            return result;
        } catch (Exception e) {
            //执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;
            //保存日志
            saveLog(point, time, OperationStatusEnum.FAIL.value());

            throw e;
        }
    }

    private void saveLog(ProceedingJoinPoint joinPoint, long time, Integer status) throws NoSuchMethodException {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = joinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(), signature.getParameterTypes());
        LogOperation annotation = method.getAnnotation(LogOperation.class);

        SysLogOperationEntity log = new SysLogOperationEntity();
        if (annotation != null) {
            //注解上的描述
            log.setOperation(annotation.value());
        }

        //登录用户信息
        UserDetail user = SecurityUser.getUser();
        if (!ObjectUtils.isEmpty(user)) {
            log.setCreatorName(user.getUsername());
        }

        log.setStatus(status);
        log.setRequestTime((int) time);

        //请求相关信息
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();

        if (!ObjectUtils.isEmpty(request)) {
            log.setIp(IpUtils.getIpAddr(request));
            log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
            log.setRequestUri(request.getRequestURI());
            log.setRequestMethod(request.getMethod());
        }

        //请求参数
        Object[] args = joinPoint.getArgs();
        try {
            String params = JSON.toJSONString(args[0]);
            log.setRequestParams(params);
        } catch (Exception ignored) {
            log.setRequestParams(ErrorCodeEnum.ENTITY_TO_JSON_ERROR.getMsg());
        }

        //保存到DB
        sysLogOperationService.save(log);
    }
}